/*
 * Copyright (C) 2012 Rothens
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package rpg;

import java.awt.*;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.io.File;
import java.io.IOException;
import java.util.Calendar;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import rpg.entities.factories.SpriteFactory;
import rpg.console.Console;
import rpg.gfx.DayNightEffect;
import rpg.gfx.FadeEffect;
import rpg.gfx.FontSets;
import rpg.gfx.MessageScreen;
import rpg.gfx.Overlay;
import rpg.gfx.Screen;
import rpg.gfx.menu.Menu;
import org.newdawn.easyogg.OggClip;

/**
 * rothens.tumblr.com
 *
 * @author Rothens
 */
public class RPG extends Canvas implements Runnable {
	
	public enum RPGPhase{
		MAIN,
		GAME,
		EDITOR,
		GAME_OVER;
	}

	private boolean running;
	private int FPS = 0;
	
	/** Layers - start */
	private BufferedImage gameLayer;
	private int[] glPixels;
	private BufferedImage overLayer;
	private int[] olPixels;
	/** Layers - end*/
	
	private Game game;	
	private Screen screen;
	private Overlay overlay;
	private Menu menu;
	private MessageScreen mscreen = null;

	private RPGPhase phase = RPGPhase.MAIN;
	private Thread thread;
	private static JFrame frame;
	
	public static int WINDOW_WIDTH = 640;
	public static int WINDOW_HEIGHT = 480;

	public static final String version = "0.0.15";
	public static RPG rpg;
	
	public static KListener keylistener = KListener.getInstance();
	public static MListener mouselistener = MListener.getInstance();
	
	public static FontSets fs = new FontSets();


	public RPG() {
		Dimension size = new Dimension(630, 470); //I dunno why is there a 10px width gap, but this will do it :D
		setSize(size);
		setMinimumSize(size);
		setMaximumSize(size);
		setPreferredSize(size);
		setFocusable(false);
		addMouseListener(mouselistener);

		screen = new Screen(WINDOW_WIDTH, WINDOW_HEIGHT);
		
		menu = new Menu(WINDOW_WIDTH, WINDOW_HEIGHT);
		addMouseMotionListener(mouselistener);

		gameLayer = new BufferedImage(WINDOW_WIDTH, WINDOW_HEIGHT, BufferedImage.TYPE_INT_RGB);
		glPixels = ((DataBufferInt) gameLayer.getRaster().getDataBuffer()).getData();

		overlay = new Overlay(WINDOW_WIDTH, WINDOW_HEIGHT);

		overLayer = new BufferedImage(WINDOW_WIDTH, WINDOW_HEIGHT, BufferedImage.TYPE_INT_ARGB);
		olPixels = ((DataBufferInt) overLayer.getRaster().getDataBuffer()).getData();

	}

	public static void main(String[] args) {
		rpg = new RPG();


		frame = new JFrame("2D RPG " + version);
		frame.setLayout(new GridLayout());

		frame.getContentPane().add(rpg);

		frame.pack();
		frame.setResizable(false); //we shouldn't allow resize manually
		frame.setLocationRelativeTo(null); //center the frame on the user's screen
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.addKeyListener(keylistener);
		frame.addMouseListener(mouselistener);
		frame.setVisible(true);
                
		rpg.start();
	}
	
	public void newGame(){
		//overlay.addOverlay(new DayNightEffect(WINDOW_WIDTH,WINDOW_HEIGHT,0x0));
		overlay.addOverlay(new FadeEffect(WINDOW_WIDTH,WINDOW_HEIGHT,true, 10));
		keylistener.clear();
		phase = RPGPhase.GAME;
		menu = null;
                rpg.StartMusic();
		Game.newInstance();
	}
        public void StartMusic() {
try {
			//OggClip ogg = new OggClip(new FileInputStream("startup2.ogg"));
			OggClip ogg = new OggClip("music.ogg");
			
			ogg.loop();
		} catch (IOException e) {
			e.printStackTrace();
		}
}
public void StopMusic() {
    try {
        OggClip ogg = new OggClip("music.ogg");
        ogg.stop();
    }
     catch (IOException e) {
			e.printStackTrace();
		}
}
	
	public void exitToMenu(){
		keylistener.clear();
		phase = RPGPhase.MAIN;
		SpriteFactory.clear();
		menu = new Menu(WINDOW_WIDTH, WINDOW_HEIGHT);
	}
	
	public void playerDeath(){
		SpriteFactory.clear();
		phase = RPGPhase.GAME_OVER;
		keylistener.clear();
		mscreen = new MessageScreen("Game Over", 0x0, (byte)0, 2){

			@Override
			public void skip() {
				exitToMenu();
			}
			
		};
	}

	public synchronized void start() {
		if (running) {
			return;
		}
		running = true;
		thread = new Thread(this);
		thread.start();
                
	}

	public synchronized void stop() {
		if (!running) {
			return;
		}
		running = false;
		try {
			thread.join();
		} catch (InterruptedException ex) {
			ex.printStackTrace();
		}
	}

	@Override
	public void run() {

		double upSec = 0;
		long lastTime = System.nanoTime();
		double secPerTick = 1 / 60.0; //60 FPS
		int cnt = 0;
		int frames = 0;

		
		while (running) {

			//FPS limit woohoo :D
			long now = System.nanoTime();
			long passed = now - lastTime;
			lastTime = now;

			if (passed < 0) {
				passed = 0;
			}

			if (passed > 100000000) {
				passed = 100000000;
			}

			upSec += passed / 1000000000.0;

			boolean ticked = false;

			while (upSec > secPerTick) {
				tick();
				upSec -= secPerTick;
				ticked = true;
				cnt++;
				if (cnt % 60 == 0) {
					FPS = frames;
					lastTime += 1000;
					frames = 0;
				}
			}
			if (ticked) {
				render();
				frames++;
			}
		}

	}
	private void tick(){
		switch(phase){
			case MAIN:
				tickMenu();
				break;
			case GAME:
				tickGame();
				break;
			case EDITOR:
				break;
			case GAME_OVER:
				tickScreen();
				break;
				
		}
	}
	
	private void render(){
		switch(phase){
			case MAIN:
				renderMenu();
				break;
			case GAME:
				renderGame();
				break;
			case EDITOR:
				break;
			case GAME_OVER:
				renderScreen();
				break;
				
		}		
	}
	
	private void tickScreen() {
		mscreen.tick();
		keylistener.tick();
		mouselistener.tick();
	}
	
	private void renderScreen() {
		BufferStrategy bfs = this.getBufferStrategy();
		if (bfs == null) {
			createBufferStrategy(2);
			return;
		}
		mscreen.render();
		System.arraycopy(mscreen.pixels, 0, glPixels, 0, WINDOW_WIDTH * WINDOW_HEIGHT);
		Graphics g = bfs.getDrawGraphics();
		//clear the screen
		g.setColor(Color.black);

		g.fillRect(0, 0, 640, 480);

		g.drawImage(gameLayer, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, null);
		g.dispose();

		bfs.show();
	}

	private void tickGame() {
		Game.getInstance().tick();
		keylistener.tick();
		mouselistener.tick();
	}

	private void renderGame() {
		BufferStrategy bfs = this.getBufferStrategy();
		if (bfs == null) {
			createBufferStrategy(2);
			return;
		}
		screen.render(game);
		overlay.render();
		System.arraycopy(screen.pixels, 0, glPixels, 0, WINDOW_WIDTH * WINDOW_HEIGHT);
		System.arraycopy(overlay.pixels, 0, olPixels, 0, WINDOW_WIDTH * WINDOW_HEIGHT);
		Graphics g = bfs.getDrawGraphics();
		//clear the screen
		g.setColor(Color.black);

		g.fillRect(0, 0, 640, 480);

		g.drawImage(gameLayer, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, null);
		g.drawImage(overLayer, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, null);
		g.setColor(Color.red);
		g.drawString(FPS + " FPS", 10, 10);
		//g.drawString("tX: " + SpriteFactory.getInstance(0).getProp().getLocation().getTileX() + " tY: " + SpriteFactory.getInstance(0).getProp().getLocation().getTileY(), 10, 20);

		g.dispose();

		bfs.show();

	}

	private void tickMenu() {
		menu.tick();
		keylistener.tick();
		mouselistener.tick();
	}
	
	private void renderMenu() {
		BufferStrategy bfs = this.getBufferStrategy();
		if (bfs == null) {
			createBufferStrategy(2);
			return;
		}
		menu.render();
		System.arraycopy(menu.pixels, 0, glPixels, 0, WINDOW_WIDTH * WINDOW_HEIGHT);
		Graphics g = bfs.getDrawGraphics();
		//clear the screen
		g.setColor(Color.black);

		g.fillRect(0, 0, 640, 480);

		g.drawImage(gameLayer, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, null);
		g.dispose();

		bfs.show();
	}
	
	public void screenShot() {
		try {
			File f = new File("screenshot");
			f.mkdir();
			//Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

			Rectangle rectangle = frame.getBounds();
			Robot robot = new Robot();
			BufferedImage image = robot.createScreenCapture(rectangle);
			File file = getPossiblePNG();
			ImageIO.write(image, "png", file);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public String getTimeString() {
		Calendar c = Calendar.getInstance();
		String ret = c.get(Calendar.YEAR) + "-" + c.get(Calendar.MONTH) + "-" + c.get(Calendar.DAY_OF_MONTH)
			+ "_" + c.get(Calendar.HOUR_OF_DAY) + "." + c.get(Calendar.MINUTE) + "." + c.get(Calendar.SECOND);
		return ret;
	}

	public File getPossiblePNG() {
		String s = getTimeString();
		File f = new File("screenshot" + File.separator + s + ".png");
		int cnt = 1;
		while (f.exists()) {
			f = new File("screenshot" + File.separator + s + "(" + cnt + ").png");
			++cnt;
		}
		return f;
	}
}